package gao.xiaolei.service;

import gao.xiaolei.dao.*;
import gao.xiaolei.dto.*;
import gao.xiaolei.entity.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import gao.xiaolei.util.RedisUtil;
import gao.xiaolei.util.ServiceName;
import gao.xiaolei.util.UuidUtil;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service("GroupService")
public class GroupService {

    @Resource(name = "GroupClassesDao")
    private GroupClassesDao groupClassesDao;

    @Resource(name = "GroupMemberDao")
    private GroupMemberDao groupMemberDao;

    @Resource(name = "GroupManageDao")
    private GroupManageDao groupManageDao;

    @Resource(name = "GroupDao")
    private GroupDao groupDao;

    @Resource(name = "UserDao")
    private UserDao userDao;

    @Resource(name = "RoleDao")
    private RoleDao roleDao;

    @Resource(name = "AuthVersionDao")
    private AuthVersionDao authVersionDao;

    @Resource(name = "UserRoleDao")
    private UserRoleDao userRoleDao;

    @Resource(name = "ClassesDao")
    private ClassesDao classesDao;

    @Autowired
    private RestTemplate restTemplate;

    @Resource(name = "ClassesGroupUserViewDao")
    private ClassesGroupUserViewDao classesGroupUserViewDao;


    @Resource(name = "RedisUtil")
    private RedisUtil redis;

    @Transactional(readOnly = true)
    //查找某个班级下面的组信息,形成树形菜单
    public List<TreeDto> findByClasses(String classes) {
        List<String> groupIds = groupClassesDao.findGroupIdByClassId(classes);
        List<Groupcs> groups = groupDao.findAllById(groupIds);
        return objToTreeDto(groups, classes);
    }

    @Transactional(readOnly = true)
    //获取用户在某个班级所属的组列表（树形结构）
    public List<TreeDto> getClassesGroupByUserIn(String classesId, String userId) {
        ClassesGroupUserView viewExample = new ClassesGroupUserView(classesId, userId);
        List<ClassesGroupUserView> groupViews = classesGroupUserViewDao.findAll(Example.of(viewExample));
        List<TreeDto> result = new ArrayList<>(groupViews.size());
        int childrenCount;
        for (int i = 0, length = groupViews.size(); i < length; i++) {
            ClassesGroupUserView view = groupViews.get(i);
            childrenCount = restTemplate.getForObject(ServiceName.TEST_SERVICE.getServiceName().concat("/testProject/count/group/").concat(view.getGroupId()), Integer.class);
            result.add(new TreeDto(view.getGroupId(), classesId, 0, childrenCount, view.getGroupName()));
        }
        return result;
    }

    @Transactional(readOnly = true)
    //获取组的详细信息
    public GroupOutDto getGroupDetail(String id) {
        Groupcs groupcs = groupDao.findById(id).orElseThrow(() -> new IllegalArgumentException("该组(".concat(id).concat(")不存在！")));
        List<GroupMember> groupMember = groupMemberDao.findAllByGroupId(id);//查找这个组下面的组员
        List<GroupMemberDto> memberDtos = new ArrayList<>(groupMember.size());
        for (int i = 0, length = groupMember.size(); i < length; i++) {//将组员信息封装进Dto
            String userName = userDao.getRealName(groupMember.get(i).getId().getUserId());
            memberDtos.add(new GroupMemberDto(groupMember.get(i).getId().getUserId(), userName, groupMember.get(i).getId().getGroupId(), groupMember.get(i).getIsLeader()));
        }
        return new GroupOutDto(groupcs.getId(), groupcs.getName(), groupcs.getDetial(), groupcs.getCreateDate(), memberDtos);
    }

    @Transactional
    //添加组到某个班级下面
    public void addClassesGroup(GroupInDto groupInDto) {
        groupDao.save(new Groupcs(groupInDto.getId(), groupInDto.getName(), groupInDto.getDescribe(), LocalDateTime.now()));
        groupClassesDao.save(new GroupClass(UuidUtil.get32Uuid(), groupInDto.getClasses(), groupInDto.getId()));
        String leader = classesDao.getLeader(groupInDto.getClasses());//获取班级的负责人
        groupManageDao.save(new GroupManage(groupInDto.getId(), leader));//将班级的负责人作为组的负责人
        Map<String, Integer> groupNewMember = groupInDto.getMember();
        for (Map.Entry<String, Integer> m : groupNewMember.entrySet()) {//然后再去修改组员信息
            groupMemberDao.save(new GroupMember(groupInDto.getId(), m.getKey(), m.getValue()));
            if (m.getValue() == 1) {
                if (groupMemberDao.getLeadGroupCount(m.getKey()) == 0)//先要查看一下新组长现在是几个组的组长,如果新组长本来不是任何组的组长
                    replaceUserRole(m.getKey(), "ROLE_GROUP_LEADER");//就要去把他的角色提示到组长角色
                refreshUserAuthVersionCache(m.getKey()); //更改了某个人的是组长的组列表，所以要将权限版本号变更
            }
        }
    }

    @Transactional
    //修改某个班级下的组信息
    public void updateClassesGroup(GroupInDto groupInDto) {
        if (!groupDao.existsById(groupInDto.getId()))
            throw new IllegalArgumentException("该组(".concat(groupInDto.getId()).concat(")不存在！"));
        groupDao.save(new Groupcs(groupInDto.getId(), groupInDto.getName(), groupInDto.getDescribe(), groupDao.getCreateDate(groupInDto.getId())));
        String newGroupLeader = null, oldGroupLeader = null;
        for (Map.Entry<String, Integer> m : groupInDto.getMember().entrySet()) {//获取新设组长
            if (m.getValue() == 1)
                newGroupLeader = m.getKey();
        }
        if (newGroupLeader != null) {//如果有设置新组长
            oldGroupLeader = groupMemberDao.queryGroupLeader(groupInDto.getId());//获取旧组长
            if (!newGroupLeader.equals(oldGroupLeader)) {//如果新旧组长不同,说明要更换组长
                if (oldGroupLeader != null) {//如果本来就有设组长的话
                    int oldLeadGroupCount = groupMemberDao.getLeadGroupCount(oldGroupLeader);//先要查看一下他现在是几个组的组长
                    if (oldLeadGroupCount <= 1)//如果现在不是一个以上组的组长的话,说明把他卸任以后就不是组长的身份了
                        replaceUserRole(oldGroupLeader, "ROLE_USER");//就要去把他的角色降低到普通用户角色
                    refreshUserAuthVersionCache(oldGroupLeader); //更改了某个人的是组长的组列表，所以要将权限版本号变更
                }
                if (groupMemberDao.getLeadGroupCount(newGroupLeader) == 0)//先要查看一下新组长现在是几个组的组长,如果新组长本来不是任何组的组长
                    replaceUserRole(newGroupLeader, "ROLE_GROUP_LEADER");//就要去把他的角色提示到组长角色
                refreshUserAuthVersionCache(newGroupLeader); //更改了某个人的是组长的组列表，所以要将权限版本号变更
            }
        }
        groupMemberDao.deleteAllByGroupId(groupInDto.getId());//修改的话则要先去删除原有的组成员信息
        Map<String, Integer> groupNewMember = groupInDto.getMember();
        for (Map.Entry<String, Integer> m : groupNewMember.entrySet()) {//然后再去修改组员信息
            groupMemberDao.save(new GroupMember(groupInDto.getId(), m.getKey(), m.getValue()));
        }
    }

    //删除某个班级下的组
    @Transactional
    public void deleteClassesGroup(String id) {
        groupDao.deleteById(id);//删除组本身
        groupClassesDao.deleteByGroupId(id);//删除组班级信息
        groupMemberDao.deleteAllByGroupId(id);//删除组成员信息
        groupManageDao.deleteAllByGroupId(id);//删除组负责人信息
        restTemplate.delete(ServiceName.TEST_SERVICE.getServiceName().concat("/testProject/group/").concat(id));//删除组下面的项目
    }

    @Transactional(readOnly = true)
    //获取某人负责的组列表信息
    public List<GroupDto> getGroupDetailByLeadingCadre(String leadingCadre) {
        List<String> groupIds = groupManageDao.queryGroupByManage(leadingCadre);
        List<Groupcs> groupcs = groupDao.findAllById(groupIds);
        List<GroupDto> dtos = new ArrayList<>(groupcs.size());
        for (int i = 0, length = groupcs.size(); i < length; i++) {
            String leaderId = groupMemberDao.queryGroupLeader(groupcs.get(i).getId());
            String leaderName = userDao.getRealName(leaderId);
            dtos.add(new GroupDto(groupcs.get(i).getId(), groupcs.get(i).getName(), leaderName));
        }
        return dtos;
    }

    @Transactional(readOnly = true)
    //获取某人所属的组列表信息
    public List<GroupDto> getGroupDetailByGroupMember(String userId) {
        List<String> groupIds = groupMemberDao.queryGroupByMember(userId);
        List<GroupDto> dtos = new ArrayList<>(0);
        if (groupIds.size() > 0) {
            List<Groupcs> groupcs = groupDao.findAllById(groupIds);
            dtos = new ArrayList<>(groupcs.size());
            for (int i = 0, length = groupcs.size(); i < length; i++) {
                String leaderId = groupMemberDao.queryGroupLeader(groupcs.get(i).getId());
                String leaderName = userDao.getRealName(leaderId);//获取组长名称
                dtos.add(new GroupDto(groupcs.get(i).getId(), groupcs.get(i).getName(), leaderName));
            }
        }
        return dtos;
    }

    //将查出来的组装进Dto
    private List<TreeDto> objToTreeDto(List<Groupcs> groups, String parentId) {
        List<TreeDto> dtos = new ArrayList<>(groups.size());
        int childrenCount;
        for (int i = 0, length = groups.size(); i < length; i++) {
            childrenCount = restTemplate.getForObject(ServiceName.TEST_SERVICE.getServiceName().concat("/testProject/count/group/").concat(groups.get(i).getId()), Integer.class);
            dtos.add(new TreeDto(groups.get(i).getId(), parentId, 0, childrenCount, groups.get(i).getName()));
        }
        return dtos;
    }

    //刷新某人的权限版本号
    private void refreshUserAuthVersionCache(String userId) {
        AuthVersion av = authVersionDao.findById(userId).orElse(new AuthVersion(userId, 0));
        av.setVersion(av.getVersion() + 1);
        authVersionDao.save(av);
        redis.set(userId, av.getVersion(), redis.EXPIRETIME);
    }

    //将某个人的一个角色替换成另一个角色
    private void replaceUserRole(String userId, String newRole) {
        userRoleDao.deleteAllByUserId(userId);//就要去把他的角色全部删除
        userRoleDao.save(new UserRole(userId, roleDao.getIdByName("ROLE_BASE")));//基础角色不能删
        userRoleDao.save(new UserRole(userId, roleDao.getIdByName(newRole)));//然后在添加新的角色信息
    }
}
